package org.zn.note.designpattern;

import java.util.ArrayList;
import java.util.List;

/**
 * 命令模式（Command Pattern）
 * 是一种数据驱动的设计模式。请求以命令的形式包裹在对象中，并传给调用对象
 * <p>
 * {@link java.util.concurrent.ThreadPoolExecutor#execute(Runnable)}
 * 就是命令模式。把一件一件的事情，封装成命令(Runnable)，给线程池执行。
 * 线程池只需要执行Runnable.run，而不关心执行了什么任务。
 */
public class Pattern15_Command {

    // Rose作为股票经纪人，只负责“接收订单”、“处理订单”
    // 具体订单本身是买单还是卖单，她不管，具体的执行动作封装在“订单”实例中
    public static void main(String[] args) {
        Broker rose = new Broker("Rose"); // 股票经纪人Rose
        rose.takeOrder( // 我给Rose一个订单
                new BuyStock( // 买入
                        new Stock("MaoTai", 10))); // 茅台10股
        rose.takeOrder( // 又给Rose一个订单
                new SellStock( // 卖出
                        new Stock("MaoTai", 5))); // 茅台5股
        rose.placeOrders(); // Rose去执行了
    }

    // 股票经纪人，可以买卖股票
    // 这里将买卖股票封装成“命令”，股票经纪人可以调用这些“命令”
    private static class Broker {
        private List<Order> orderList = new ArrayList<>(); // 要处理的订单，就是买卖股票的订单
        private String name;

        Broker(String name) {
            this.name = name;
        }

        void takeOrder(Order order) { // 接收一个订单
            orderList.add(order);
        }

        void placeOrders() { // 处理订单
            for (Order order : orderList) {
                order.execute();
            }
            orderList.clear();
        }
    }

    // 股票订单：有买单和卖单
    private interface Order {
        void execute();
    }

    // 买单
    private static class BuyStock implements Order {
        private Stock stock;

        BuyStock(Stock stock) {
            this.stock = stock;
        }

        public void execute() {
            stock.buy();
        }
    }

    // 卖单
    public static class SellStock implements Order {
        private Stock stock;

        SellStock(Stock stock) {
            this.stock = stock;
        }

        public void execute() {
            stock.sell();
        }
    }

    // 股票
    private static class Stock {
        private String name;
        private int quantity;

        Stock(String name, int quantity) {
            this.name = name;
            this.quantity = quantity;
        }

        void buy() {
            System.out.println("Stock [ Name: " + name + ", Quantity: " + quantity + " ] bought");
        }

        void sell() {
            System.out.println("Stock [ Name: " + name + ", Quantity: " + quantity + " ] sold");
        }
    }
}
